package com.migu.spms.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.migu.spms.constant.Constant;
import com.migu.spms.dao.entity.ChangeHistoryCriteria;
import com.migu.spms.dao.entity.FunctionRequireCriteria;
import com.migu.spms.dao.entity.FunctionRequireDO;
import com.migu.spms.dao.entity.FunctionRequirementCorrelationRequireCriteria;
import com.migu.spms.dao.entity.FunctionRequirementCorrelationRequireDO;
import com.migu.spms.dao.entity.RequireAttachmentCriteria;
import com.migu.spms.dao.entity.RequireAttachmentDO;
import com.migu.spms.dao.entity.RequireUserCriteria;
import com.migu.spms.dao.entity.RequireUserDO;
import com.migu.spms.dao.entity.SubParentRequireCriteria;
import com.migu.spms.dao.entity.SubParentRequireDO;
import com.migu.spms.dao.inf.IBaseLineDO;
import com.migu.spms.dao.inf.IChangeHistoryDO;
import com.migu.spms.dao.inf.IFunctionRequireDO;
import com.migu.spms.dao.inf.IFunctionRequirementCorrelationRequireDO;
import com.migu.spms.dao.inf.IRequireAttachmentDO;
import com.migu.spms.dao.inf.IRequireUserDO;
import com.migu.spms.dao.inf.ISubParentRequireDO;
import com.migu.spms.service.data.User;
import com.migu.spms.service.inf.ICreateBaselineService;
import com.migu.spms.service.inf.IFunctionFlowService;
import com.migu.spms.service.inf.ISequenceCreateService;
import com.migu.spms.utils.CodeCreateUtil;
import com.migu.spms.utils.PropertiesCopyUtil;
import com.migu.spms.utils.RequestValidateUtil;
import com.migu.spms.utils.exception.ServiceException;
import com.migu.spms.webapi.data.CreateBaselineRequest;

/**
 * 
* 项目名称:  SPMS需求管理
* 包:        com.migu.spms.service.impl 
* 类名称:    CreateRequireServiceImpl.java
* 类描述:    新建基线业务实现类
* 创建人:    fw  
* 创建时间:  2017年6月19日 下午2:40:36
 */
@Transactional
@Component(value = "createBaselineService")
public class CreateBaselineServiceImpl implements ICreateBaselineService {
    private static Logger logger = LoggerFactory.getLogger(CreateBaselineServiceImpl.class);

    @Resource(name = "IFunctionRequireDO")
    private IFunctionRequireDO functionRequireDAO;
    @Resource(name = "sequenceService")
    private ISequenceCreateService sequenceService;
    @Resource(name = "IRequireAttachmentDO")
    private IRequireAttachmentDO requireAttachmentDAO;
    @Resource(name = "ISubParentRequireDO")
    private ISubParentRequireDO subParentRequireDAO;
    @Resource(name = "IBaseLineDO")
    private IBaseLineDO baseLineDAO;
    @Resource(name = "IFunctionRequirementCorrelationRequireDO")
    private IFunctionRequirementCorrelationRequireDO frcrDAO;
    @Resource(name = "IRequireUserDO")
    private IRequireUserDO requireUserDAO;
    @Resource(name = "IChangeHistoryDO")
    private IChangeHistoryDO changeHistoryDAO;
    @Resource(name = "functionFlowServiceImpl")
    private IFunctionFlowService functionFlowService;

    /**
     * 新建基线
    * @param createRequireRequest
    * @param user
    * @return
    * @throws Exception
     */
    @Override
    public Boolean create(CreateBaselineRequest createBaselineRequest, User user) throws Exception {
        RequestValidateUtil.validateCreateBaselineRequest(createBaselineRequest);
        for (Long functionRequireId : createBaselineRequest.getFunctionRequireIds()) {
            FunctionRequireDO functionRequireDO = functionRequireDAO.selectByPrimaryKey(functionRequireId);
            if (null == functionRequireDO) {
                logger.error(CodeCreateUtil.createLogMessage("CreateBaselineServiceImpl.create",
                        "新建基线[根据需求id" + functionRequireId.longValue() + "查询需求为空]"));
                throw new ServiceException("新建基线失败，请重试！");
            }
            if (Constant.LogicVariable.NO_INT.intValue() == functionRequireDO.getIsBaseLine().intValue()) {
                FunctionRequireCriteria functionRequireCriteria = new FunctionRequireCriteria();
                functionRequireCriteria.setId(functionRequireDO.getId());
                functionRequireCriteria.setBaselineVersion(createBaselineRequest.getVersion());
                functionRequireDAO.updateByPrimaryKeySelective(functionRequireCriteria);
                insertOperateHistory(functionRequireCriteria, functionRequireCriteria.getId(), user,
                        functionRequireCriteria.getBaselineVersion(), false);
            } else {
                FunctionRequireCriteria functionRequireCriteria = PropertiesCopyUtil.parse(functionRequireDO,
                        FunctionRequireCriteria.class);
                functionRequireCriteria.setBaselineVersion(createBaselineRequest.getVersion());
                functionRequireCriteria.setId(null);
                functionRequireCriteria.setCurrentHandlerId(functionRequireDO.getDevelopResponsibleId());
                functionRequireCriteria.setCurrentHandlerName(functionRequireDO.getDevelopResponsibleName());
                functionRequireCriteria.setFlowInfo(null);
                functionRequireCriteria.setIsBaseLine(Constant.LogicVariable.NO_INT);
                functionRequireCriteria.setProcessInstanceId(null);
                functionRequireCriteria.setStatus(Constant.flowStatus.NEWING);
                functionRequireCriteria.setTaskId(null);
                functionRequireCriteria.setCreatorId(Long.valueOf(user.getUserId()));
                functionRequireCriteria.setCreatorName(user.getUserName());
                functionRequireCriteria.setCreateTime(new Date());
                // functionRequireCriteria.setRequireId(
                // CodeCreateUtil.createRequireId(functionRequireDO.getProjectId(),
                // sequenceService.getRequireNumber()));
                functionRequireDAO.insertSelective(functionRequireCriteria);
                // 关联人员信息（代发人员，测试人员）
                copyUser(functionRequireDO, functionRequireCriteria.getId());
                // 关联子需求信息
                relateSubrequire(functionRequireDO, functionRequireCriteria.getId());
                // 关联附件信息
                copyAttachment(functionRequireDO, functionRequireCriteria.getId(), user);
                // 关联关联需求信息
                relateOtherRequire(functionRequireDO, functionRequireCriteria.getId());
                // 插入操作历史
                functionFlowService.startProcessFlow(functionRequireCriteria.getId(), user);
                insertOperateHistory(functionRequireCriteria, functionRequireCriteria.getId(), user,
                        functionRequireDO.getBaselineVersion(), true);
            }
        }
        return true;
    }

    /** 复制原基线的测试和开发信息到新基线需求
     * @Description 
     * @param functionRequireDO
     * @param baselineRequireId
     */
    private void copyUser(FunctionRequireDO functionRequireDO, Long baselineRequireId) {
        // copy developers information to new baseline requirement
        RequireUserCriteria requireUserCriteria = new RequireUserCriteria();
        requireUserCriteria.setFunctionRequireId(functionRequireDO.getId());
        requireUserCriteria.setRoleId(Constant.Role.DEVELOPER);
        List<RequireUserDO> developers = requireUserDAO.selectByCriteria(requireUserCriteria);
        if (null != developers && developers.size() > 0) {
            List<RequireUserCriteria> developers4Insert = new ArrayList<>();
            for (RequireUserDO requireUserDO : developers) {
                RequireUserCriteria developer = PropertiesCopyUtil.parse(requireUserDO, RequireUserCriteria.class);
                developer.setFunctionRequireId(baselineRequireId);
                developer.setId(null);
                developers4Insert.add(developer);
            }
            requireUserDAO.batchInsert(developers4Insert);
        }
        // copy testers information to new baseline requirement
        requireUserCriteria.setRoleId(Constant.Role.TESTER);
        List<RequireUserDO> testers = requireUserDAO.selectByCriteria(requireUserCriteria);
        if (null != testers && testers.size() > 0) {
            List<RequireUserCriteria> testers4Insert = new ArrayList<>();
            for (RequireUserDO requireUserDO : testers) {
                RequireUserCriteria tester = PropertiesCopyUtil.parse(requireUserDO, RequireUserCriteria.class);
                tester.setFunctionRequireId(baselineRequireId);
                tester.setId(null);
                testers4Insert.add(tester);
            }
            requireUserDAO.batchInsert(testers4Insert);
        }
    }

    /**
     * @Description 关联旧版本的父子需求到新基线需求
     * @param functionRequireDO
     * @param baselineRequireId
     */
    private void relateSubrequire(FunctionRequireDO functionRequireDO, Long baselineRequireId) {
        SubParentRequireCriteria subParentRequireCriteria = new SubParentRequireCriteria();
        subParentRequireCriteria.setParentRequireId(functionRequireDO.getId());
        List<SubParentRequireDO> subParentRequireDOs = subParentRequireDAO.selectByCriteria(subParentRequireCriteria);
        // relate earlier requirement`s subrequirements information to new
        // baseline requirement
        if (null != subParentRequireDOs && subParentRequireDOs.size() > 0) {
            List<SubParentRequireCriteria> asParentRequire = new ArrayList<>();
            for (SubParentRequireDO subParentRequireDO : subParentRequireDOs) {
                SubParentRequireCriteria subParentRequireCriteria2 = PropertiesCopyUtil.parse(subParentRequireDO,
                        SubParentRequireCriteria.class);
                subParentRequireCriteria2.setId(null);
                subParentRequireCriteria2.setParentRequireId(baselineRequireId);
                asParentRequire.add(subParentRequireCriteria2);
            }
            subParentRequireDAO.batchInsert(asParentRequire);
        }
        // relate earlier requirement`s subrequirements information to new
        // baseline requirement
        subParentRequireCriteria.setParentRequireId(null);
        subParentRequireCriteria.setSubRequireId(functionRequireDO.getId());
        List<SubParentRequireDO> subParentRequireDOs2 = subParentRequireDAO.selectByCriteria(subParentRequireCriteria);
        if (null != subParentRequireDOs2 && subParentRequireDOs2.size() > 0) {
            List<SubParentRequireCriteria> asSubrequire = new ArrayList<>();
            for (SubParentRequireDO subParentRequireDO : subParentRequireDOs2) {
                SubParentRequireCriteria subParentRequireCriteria2 = PropertiesCopyUtil.parse(subParentRequireDO,
                        SubParentRequireCriteria.class);
                subParentRequireCriteria2.setId(null);
                subParentRequireCriteria2.setSubRequireId(baselineRequireId);
                asSubrequire.add(subParentRequireCriteria2);
            }
            subParentRequireDAO.batchInsert(asSubrequire);
        }
    }

    /**
     * @Description 关联旧版本的关联需求到新基线版本
     * @param functionRequireDO
     * @param baselineRequireId
     */
    private void relateOtherRequire(FunctionRequireDO functionRequireDO, Long baselineRequireId) {
        FunctionRequirementCorrelationRequireCriteria frCriteria = new FunctionRequirementCorrelationRequireCriteria();
        frCriteria.setFunctionRequireId(functionRequireDO.getId().toString());
        List<FunctionRequirementCorrelationRequireDO> frCorrelationRequireDOs = frcrDAO.selectByCriteria(frCriteria);
        if (null != frCorrelationRequireDOs && frCorrelationRequireDOs.size() > 0) {
            List<FunctionRequirementCorrelationRequireCriteria> frcrCriteria4insert = new ArrayList<>();
            for (FunctionRequirementCorrelationRequireDO fDO : frCorrelationRequireDOs) {
                FunctionRequirementCorrelationRequireCriteria temp = PropertiesCopyUtil.parse(fDO,
                        FunctionRequirementCorrelationRequireCriteria.class);
                temp.setFunctionRequireId(baselineRequireId.toString());
                frcrCriteria4insert.add(temp);
            }
            frcrDAO.batchInsert(frcrCriteria4insert);
        }
    }

    /**
     * @Description 关联旧基线版本的附件信息到新基线需求（仅信息复制，文件共享） 
     * @param functionRequireDO
     * @param baselineRequireId
     * @param user
     */
    private void copyAttachment(FunctionRequireDO functionRequireDO, Long baselineRequireId, User user) {
        RequireAttachmentCriteria requireAttachmentCriteria = new RequireAttachmentCriteria();
        requireAttachmentCriteria.setFunctionRequireId(functionRequireDO.getId());
        List<RequireAttachmentDO> requireAttachmentDOs = requireAttachmentDAO
                .selectByCriteria(requireAttachmentCriteria);
        if (null != requireAttachmentDOs && requireAttachmentDOs.size() > 0) {
            List<RequireAttachmentCriteria> requireAttachmentCriterias4Insert = new ArrayList<>();
            for (RequireAttachmentDO requireAttachmentDO : requireAttachmentDOs) {
                RequireAttachmentCriteria requireAttachmentCriteriaNew = PropertiesCopyUtil.parse(requireAttachmentDO,
                        RequireAttachmentCriteria.class);
                requireAttachmentCriteriaNew.setFunctionRequireId(baselineRequireId);
                requireAttachmentCriteriaNew.setUploaderId(Long.valueOf(user.getUserId()));
                requireAttachmentCriteriaNew.setUploaderName(user.getUserName());
                requireAttachmentCriteriaNew.setUploadTime(new Date());
                requireAttachmentCriterias4Insert.add(requireAttachmentCriteriaNew);
            }
            requireAttachmentDAO.batchInsert(requireAttachmentCriterias4Insert);
        }
    }

    /**
     * @Description 插入操作历史 
     * @param functionRequireDO
     * @param user
     */
    private void insertOperateHistory(FunctionRequireCriteria functionRequireCriteria, Long functionRequireId,
            User user, String oldVersion, boolean isBased) {
        ChangeHistoryCriteria changeHistoryCriteria = new ChangeHistoryCriteria();
        changeHistoryCriteria.setBaselineVersion(functionRequireCriteria.getBaselineVersion());
        changeHistoryCriteria.setFunctionRequireId(functionRequireCriteria.getId());
        changeHistoryCriteria.setCreateId(Long.valueOf(user.getUserId()));
        changeHistoryCriteria.setCreateName(user.getUserName());
        changeHistoryCriteria.setOperateType(Constant.OperateType.CREATE_BASELINE);
        changeHistoryCriteria.setCreateTime(new Date());
        changeHistoryCriteria.setIsPermit(Constant.LogicVariable.NO_INT.toString());
        changeHistoryCriteria.setIsDetails(Constant.LogicVariable.NO_INT.toString());
        changeHistoryCriteria.setRemark(
                CodeCreateUtil.createBaselineRemark(oldVersion, functionRequireCriteria.getBaselineVersion(), isBased));
        changeHistoryDAO.insertSelective(changeHistoryCriteria);
    }
}
